var read_line = require('readline-sync')
read_line.setDefaultOptions({ prompt: '' })
var read_line = read_line.prompt

let t = parseInt(read_line()) // 读出T
for (let i = 0; i < t; i++) {
  let [n, m, k, x] = read_line().split(' ').map((item) => parseInt(item)) // 转成数组  n表示行 m表示列 k表示数字智能是+k或-k x表示和为x
  let matrix = [] // 保留这个数组
  for (let j = 0; j < n; j++) {
    let arr = read_line().split(' ').map((item) => parseInt(item)) // 转换成数组
    matrix.push(arr) // 将这个数组放入矩阵中
  }
  // 判断从左上角走到右下角 能不能让和等于x
  if (fnDp(matrix, n, m, x, k)) {
    console.log('yes')
  } else {
    console.log('no')
  }
}
function fnDp (matrix, n, m, x, k) {
  if (x % Math.abs(k) !== 0) return false // 不是倍数不行
  let dp = new Array(n).fill(0).map(() => new Array(m).fill(new Set()))
  console.log(dp)
  dp[0][0].add(matrix[0][0])
  for (let i = 1; i < n; i++) {
    let arr5 = [...dp[i - 1][0]]
    let num = arr5[0] + matrix[i][0]
    dp[i][0] = new Set() // 初始化这一个的第一列
    dp[i][0].add(num)
  }
  for (let i = 1; i < m; i++) {
    let arr4 = [...dp[0][i - 1]]
    let num = arr4[0] + matrix[0][i]
    // console.log(dp[0][i])
    dp[0][i] = new Set()
    dp[0][i].add(num) // 初始化第一行的数据
  }
  for (let i = 1; i < n; i++) {
    for (let j = 1; j < m; j++) {
      let arr1 = [...dp[i - 1][j]]
      dp[i][j] = new Set()
      for (let q = 0; q < arr1.length; q++) {
        dp[i][j].add(arr1[q] + matrix[i][j]) // 吧这个加入到dp[i][j]中
      }
      let arr2 = [...dp[i][j - 1]]
      for (let q = 0; q < arr2.length; q++) {
        dp[i][j].add(arr2[q] + matrix[i][j])
      }
    }
  }
  // 遍历完之后
  // 判断dp[n-1][m-1]中是不是有x
  let arr3 = [...dp[n - 1][m - 1]]
  return arr3.includes(x)
}